<!DOCTYPE HTML>
<html lang="zh-CN">


<head>
    <meta charset="utf-8">
    <meta name="keywords" content="FFmpeg笔记(四), jiodg45的博客">
    <meta name="description" content="">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <!-- Global site tag (gtag.js) - Google Analytics -->


    <title>FFmpeg笔记(四) | jiodg45的博客</title>
    <link rel="icon" type="image/png" href="/jiodg45/favicon.png">

    <link rel="stylesheet" type="text/css" href="/jiodg45/libs/awesome/css/all.css">
    <link rel="stylesheet" type="text/css" href="/jiodg45/libs/materialize/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/jiodg45/libs/aos/aos.css">
    <link rel="stylesheet" type="text/css" href="/jiodg45/libs/animate/animate.min.css">
    <link rel="stylesheet" type="text/css" href="/jiodg45/libs/lightGallery/css/lightgallery.min.css">
    <link rel="stylesheet" type="text/css" href="/jiodg45/css/matery.css">
    <link rel="stylesheet" type="text/css" href="/jiodg45/css/my.css">

    <script src="/jiodg45/libs/jquery/jquery.min.js"></script>

<meta name="generator" content="Hexo 5.4.0">
<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
</head>




<body>
    <header class="navbar-fixed">
    <nav id="headNav" class="bg-color nav-transparent">
        <div id="navContainer" class="nav-wrapper container">
            <div class="brand-logo">
                <a href="/jiodg45/" class="waves-effect waves-light">
                    
                    <img src="/jiodg45/medias/logo.png" class="logo-img" alt="LOGO">
                    
                    <span class="logo-span">jiodg45的博客</span>
                </a>
            </div>
            

<a href="#" data-target="mobile-nav" class="sidenav-trigger button-collapse"><i class="fas fa-bars"></i></a>
<ul class="right nav-menu">
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/jiodg45/" class="waves-effect waves-light">
      
      <i class="fas fa-home" style="zoom: 0.6;"></i>
      
      <span>首页</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/jiodg45/tags" class="waves-effect waves-light">
      
      <i class="fas fa-tags" style="zoom: 0.6;"></i>
      
      <span>标签</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/jiodg45/categories" class="waves-effect waves-light">
      
      <i class="fas fa-bookmark" style="zoom: 0.6;"></i>
      
      <span>分类</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/jiodg45/archives" class="waves-effect waves-light">
      
      <i class="fas fa-archive" style="zoom: 0.6;"></i>
      
      <span>归档</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/jiodg45/about" class="waves-effect waves-light">
      
      <i class="fas fa-user-circle" style="zoom: 0.6;"></i>
      
      <span>关于</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/jiodg45/contact" class="waves-effect waves-light">
      
      <i class="fas fa-comments" style="zoom: 0.6;"></i>
      
      <span>留言板</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/jiodg45/friends" class="waves-effect waves-light">
      
      <i class="fas fa-address-book" style="zoom: 0.6;"></i>
      
      <span>友情链接</span>
    </a>
    
  </li>
  
  <li>
    <a href="#searchModal" class="modal-trigger waves-effect waves-light">
      <i id="searchIcon" class="fas fa-search" title="搜索" style="zoom: 0.85;"></i>
    </a>
  </li>
</ul>


<div id="mobile-nav" class="side-nav sidenav">

    <div class="mobile-head bg-color">
        
        <img src="/jiodg45/medias/logo.png" class="logo-img circle responsive-img">
        
        <div class="logo-name">jiodg45的博客</div>
        <div class="logo-desc">
            
            Never really desperate, only the lost of the soul.
            
        </div>
    </div>

    

    <ul class="menu-list mobile-menu-list">
        
        <li class="m-nav-item">
	  
		<a href="/jiodg45/" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-home"></i>
			
			首页
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/jiodg45/tags" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-tags"></i>
			
			标签
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/jiodg45/categories" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-bookmark"></i>
			
			分类
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/jiodg45/archives" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-archive"></i>
			
			归档
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/jiodg45/about" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-user-circle"></i>
			
			关于
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/jiodg45/contact" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-comments"></i>
			
			留言板
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/jiodg45/friends" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-address-book"></i>
			
			友情链接
		</a>
          
        </li>
        
        
        <li><div class="divider"></div></li>
        <li>
            <a href="https://github.com/blinkfox/hexo-theme-matery" class="waves-effect waves-light" target="_blank">
                <i class="fab fa-github-square fa-fw"></i>Fork Me
            </a>
        </li>
        
    </ul>
</div>


        </div>

        
            <style>
    .nav-transparent .github-corner {
        display: none !important;
    }

    .github-corner {
        position: absolute;
        z-index: 10;
        top: 0;
        right: 0;
        border: 0;
        transform: scale(1.1);
    }

    .github-corner svg {
        color: #0f9d58;
        fill: #fff;
        height: 64px;
        width: 64px;
    }

    .github-corner:hover .octo-arm {
        animation: a 0.56s ease-in-out;
    }

    .github-corner .octo-arm {
        animation: none;
    }

    @keyframes a {
        0%,
        to {
            transform: rotate(0);
        }
        20%,
        60% {
            transform: rotate(-25deg);
        }
        40%,
        80% {
            transform: rotate(10deg);
        }
    }
</style>

<a href="https://github.com/blinkfox/hexo-theme-matery" class="github-corner tooltipped hide-on-med-and-down" target="_blank"
   data-tooltip="Fork Me" data-position="left" data-delay="50">
    <svg viewBox="0 0 250 250" aria-hidden="true">
        <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
        <path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
              fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
        <path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
              fill="currentColor" class="octo-body"></path>
    </svg>
</a>
        
    </nav>

</header>

    



<div class="bg-cover pd-header post-cover" style="background-image: url('/jiodg45/medias/featureimages/3.jpg')">
    <div class="container" style="right: 0px;left: 0px;">
        <div class="row">
            <div class="col s12 m12 l12">
                <div class="brand">
                    <h1 class="description center-align post-title">FFmpeg笔记(四)</h1>
                </div>
            </div>
        </div>
    </div>
</div>




<main class="post-container content">

    
    <link rel="stylesheet" href="/jiodg45/libs/tocbot/tocbot.css">
<style>
    #articleContent h1::before,
    #articleContent h2::before,
    #articleContent h3::before,
    #articleContent h4::before,
    #articleContent h5::before,
    #articleContent h6::before {
        display: block;
        content: " ";
        height: 100px;
        margin-top: -100px;
        visibility: hidden;
    }

    #articleContent :focus {
        outline: none;
    }

    .toc-fixed {
        position: fixed;
        top: 64px;
    }

    .toc-widget {
        width: 345px;
        padding-left: 20px;
    }

    .toc-widget .toc-title {
        padding: 35px 0 15px 17px;
        font-size: 1.5rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    .toc-widget ol {
        padding: 0;
        list-style: none;
    }

    #toc-content {
        padding-bottom: 30px;
        overflow: auto;
    }

    #toc-content ol {
        padding-left: 10px;
    }

    #toc-content ol li {
        padding-left: 10px;
    }

    #toc-content .toc-link:hover {
        color: #42b983;
        font-weight: 700;
        text-decoration: underline;
    }

    #toc-content .toc-link::before {
        background-color: transparent;
        max-height: 25px;

        position: absolute;
        right: 23.5vw;
        display: block;
    }

    #toc-content .is-active-link {
        color: #42b983;
    }

    #floating-toc-btn {
        position: fixed;
        right: 15px;
        bottom: 76px;
        padding-top: 15px;
        margin-bottom: 0;
        z-index: 998;
    }

    #floating-toc-btn .btn-floating {
        width: 48px;
        height: 48px;
    }

    #floating-toc-btn .btn-floating i {
        line-height: 48px;
        font-size: 1.4rem;
    }
</style>
<div class="row">
    <div id="main-content" class="col s12 m12 l9">
        <!-- 文章内容详情 -->
<div id="artDetail">
    <div class="card">
        <div class="card-content article-info">
            <div class="row tag-cate">
                <div class="col s7">
                    
                    <div class="article-tag">
                        
                            <a href="/jiodg45/tags/audio/">
                                <span class="chip bg-color">audio</span>
                            </a>
                        
                            <a href="/jiodg45/tags/ffmpeg/">
                                <span class="chip bg-color">ffmpeg</span>
                            </a>
                        
                    </div>
                    
                </div>
                <div class="col s5 right-align">
                    
                    <div class="post-cate">
                        <i class="fas fa-bookmark fa-fw icon-category"></i>
                        
                            <a href="/jiodg45/categories/ffmpeg/" class="post-category">
                                ffmpeg
                            </a>
                        
                    </div>
                    
                </div>
            </div>

            <div class="post-info">
                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-minus fa-fw"></i>发布日期:&nbsp;&nbsp;
                    2021-03-11
                </div>
                

                

                

                

                
            </div>
        </div>
        <hr class="clearfix">

        

        

        <div class="card-content article-card-content">
            <div id="articleContent">
                <h2 id="FFmpeg编解码基本流程"><a href="#FFmpeg编解码基本流程" class="headerlink" title="FFmpeg编解码基本流程"></a>FFmpeg编解码基本流程</h2><ul>
<li>下面是一个文件格式的基本转换流程,</li>
</ul>
<p>a.<code>libavformat.a</code>提供<code>demuxer</code>和<code>muxer</code>,它是音视频文件容器的拆包解包工厂,encoded data packets对应的是<code>AVPacket</code>(音视频数据包).<br>b. <code>libavcodec.a</code>提供<code>decoder</code>和<code>encoder</code>,对上游传递过的来的<code>AVPacket</code>进行编解码,的到<code>AVFrame</code>(视频帧,或音频帧,多个音频帧),音视频的压缩和特效实现就是针对<code>AVFrame</code>进行处理的。<br>c. 处理后的音视频帧可以再次封装成文件,或是继续转换生成pixel buff提交给渲染器展示输出.</p>
<figure class="highlight text"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"> _______              ______________</span><br><span class="line">|       |            |              |</span><br><span class="line">| input |  demuxer   | encoded data |   decoder</span><br><span class="line">| file  | ---------&gt; | packets      | -----+</span><br><span class="line">|_______|            |______________|      |</span><br><span class="line">                                           v</span><br><span class="line">                                       _________</span><br><span class="line">                                      |         |</span><br><span class="line">                                      | decoded |</span><br><span class="line">                                      | frames  |</span><br><span class="line">                                      |_________|</span><br><span class="line"> ________             ______________       |</span><br><span class="line">|        |           |              |      |</span><br><span class="line">| output | &lt;-------- | encoded data | &lt;----+</span><br><span class="line">| file   |   muxer   | packets      |   encoder</span><br><span class="line">|________|           |______________|</span><br><span class="line"></span><br></pre></td></tr></tbody></table></figure>

<ul>
<li>基于上面的转换流程,在decode frames后进行一些特效处理,这一过程主要有<code>libavfilter</code>来实现,通常用来设置视频的滤镜效果</li>
</ul>
<figure class="highlight text"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"> _________                        ______________</span><br><span class="line">|         |                      |              |</span><br><span class="line">| decoded |                      | encoded data |</span><br><span class="line">| frames  |\                   _ | packets      |</span><br><span class="line">|_________| \                  /||______________|</span><br><span class="line">             \   __________   /</span><br><span class="line">  simple     _\||          | /  encoder</span><br><span class="line">  filtergraph   | filtered |/</span><br><span class="line">                | frames   |</span><br><span class="line">                |__________|</span><br></pre></td></tr></tbody></table></figure>



<ul>
<li>输入输出不仅仅局限于文件,还可以接收和输出流媒体,可以通过<code>ffmpeg -protocls</code>查看音视频支持的流媒体转换,这里累列举常用的流媒体协议,每一种一些都有一特定的首部字段来定义如何实现流媒体的互转操作. 所谓的推流拉流无非就是按照对应的协议规范,将音视频流按照协议封装后输出和输出.</li>
</ul>
<figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">file</span><br><span class="line">http</span><br><span class="line">https </span><br><span class="line">pipe </span><br><span class="line">rtmp</span><br><span class="line">rtmps </span><br><span class="line">rtp </span><br><span class="line">tcp</span><br><span class="line">tls</span><br><span class="line">udp </span><br><span class="line">...</span><br></pre></td></tr></tbody></table></figure>

<h2 id="FFmpeg-本地调试"><a href="#FFmpeg-本地调试" class="headerlink" title="FFmpeg-本地调试"></a>FFmpeg-本地调试</h2><p>如果前面已经安装了ffmpeg这里就非常快了,如果是mac电脑,可以使用xcode来debug:<br>先说下集成步骤,如果对Xcode不属性可以参考这篇博客<code>https://www.jianshu.com/p/226c19aa6e42</code>,图文并茂的描述了集成步骤</p>
<p>a. 下载ffmpeg并成功安装<br>b. 新建一个C工程,将<code>FFmpeg</code>源文件全部拖入到工程,注意: <code>create exteneral build system project</code>不要勾选<br>c. 然后设置Header Search Path和Library Search Path,和之前集成FFmpeg到iOS工程的步相似，header选择我们可以统一将所有header引入<br>d. 然后创建一个<code>external build system</code>的target<br>f. 选择<code>executable</code>,点击other找到你需要debug的<code>ffmpeg.g</code>的debug文件.<br>g. 设置启动的运行参数,传递给<code>ffmpeg.c</code>文件的main函数.</p>
<p>在<code>ffmpeg.c</code>文件中加上断点,点击运行,这里可以看到调试器的基本信息</p>
<figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">ffmpeg_g was compiled with optimization - stepping may behave oddly; variables may not be available.</span><br><span class="line">(lldb) p outdev_list</span><br><span class="line">(const AVOutputFormat *const [2]) $0 = {</span><br><span class="line">  [0] = 0x00000001012b90d0</span><br><span class="line">  [1] = 0x0000000000000000</span><br><span class="line">} </span><br><span class="line">Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/qxq4633/ffmpegdemo/input.mov':</span><br><span class="line">  Metadata:</span><br><span class="line">    major_brand     : qt  </span><br><span class="line">    minor_version   : 0</span><br><span class="line">    compatible_brands: qt  </span><br><span class="line">    creation_time   : 2021-02-05T02:51:34.000000Z</span><br><span class="line">    com.apple.quicktime.make: Apple</span><br><span class="line">    com.apple.quicktime.model: MacBookPro15,1</span><br><span class="line">    com.apple.quicktime.software: Mac OS X 10.15.6 (19G2021)</span><br><span class="line">    com.apple.quicktime.creationdate: 2021-02-05T10:50:55+0800</span><br><span class="line">  Duration: 00:00:26.63, start: 0.000000, bitrate: 2028 kb/s</span><br><span class="line">    Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709), 766x1334 [SAR 1:1 DAR 383:667], 2015 kb/s, 59.93 fps, 60 tbr, 6k tbn, 12k tbc (default)</span><br><span class="line">    Metadata:</span><br><span class="line">      creation_time   : 2021-02-05T02:51:34.000000Z</span><br><span class="line">      handler_name    : Core Media Video</span><br><span class="line">      encoder         : H.264</span><br><span class="line">At least one output file must be specified</span><br><span class="line">Program ended with exit code: 1</span><br></pre></td></tr></tbody></table></figure>

<h2 id="FFmpeg-main函数相关的主要步骤"><a href="#FFmpeg-main函数相关的主要步骤" class="headerlink" title="FFmpeg main函数相关的主要步骤"></a>FFmpeg main函数相关的主要步骤</h2><ol>
<li>注册程序退出时的cleanup函数</li>
<li>注册复用器</li>
<li>解析传入的参数</li>
<li>设置全局变量</li>
</ol>
<figure class="highlight c"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">uint8_t</span> *subtitle_out;</span><br><span class="line">InputStream **input_streams = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">int</span>        nb_input_streams = <span class="number">0</span>;</span><br><span class="line">InputFile   **input_files   = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">int</span>        nb_input_files   = <span class="number">0</span>;</span><br><span class="line">OutputStream **output_streams = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">int</span>         nb_output_streams = <span class="number">0</span>;</span><br><span class="line">OutputFile   **output_files   = <span class="literal">NULL</span>;</span><br><span class="line"><span class="keyword">int</span>         nb_output_files   = <span class="number">0</span>;</span><br><span class="line">FilterGraph **filtergraphs;</span><br><span class="line"><span class="keyword">int</span>        nb_filtergraphs;</span><br></pre></td></tr></tbody></table></figure>

<ol start="5">
<li>打开输入文件,获取文件信息，并通过指定复用进行解包,将解包的AVPacket传入到InputStream中</li>
<li>InputStream通过它关联的AVFomartContext和AVFilterGraph(滤波器)获取便捷码信息</li>
<li>查找并创建对应的<code>Codec</code>进行编解码</li>
<li>通过指定的AVFilter为图像添加滤镜效果</li>
<li>最后通过复用器将文件进行包装</li>
</ol>
<h2 id="FFmpeg-main函数-ffmpeg-cleanup"><a href="#FFmpeg-main函数-ffmpeg-cleanup" class="headerlink" title="FFmpeg main函数-ffmpeg_cleanup"></a>FFmpeg main函数-ffmpeg_cleanup</h2><p>注册<code>ffmpeg_cleanup</code>函数,用于清除程序退出时的资源</p>
<p>输入输出的Files,Streams,Filters,用于批量处理Filter的FilterGraph,以及它们所关联的子属性</p>
<figure class="highlight c"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">ffmpeg_cleanup</span><span class="params">(<span class="keyword">int</span> ret)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">    <span class="keyword">int</span> i, j;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (do_benchmark) {</span><br><span class="line">        <span class="keyword">int</span> maxrss = getmaxrss() / <span class="number">1024</span>;</span><br><span class="line">        av_log(<span class="literal">NULL</span>, AV_LOG_INFO, <span class="string">"bench: maxrss=%ikB\n"</span>, maxrss);</span><br><span class="line">    }</span><br><span class="line">    <span class="comment">//1. 释放全局的`FilterGraph`想关联的属性,这些关联的对象按照指针的顺序连接起来就是一个不规则的树，</span></span><br><span class="line">    <span class="comment">//   按顺序一次从树的底部到根节点,最后全部释放</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; nb_filtergraphs; i++) {</span><br><span class="line">        FilterGraph *fg = filtergraphs[i];</span><br><span class="line">        avfilter_graph_free(&amp;fg-&gt;graph);</span><br><span class="line">        <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; fg-&gt;nb_inputs; j++) {</span><br><span class="line">            <span class="comment">//1.1 获取FilterGraph所关联的`InputFilter`列表</span></span><br><span class="line">            InputFilter *ifilter = fg-&gt;inputs[j];</span><br><span class="line">            <span class="comment">//1.2 获取InputFilter关联的InputStream</span></span><br><span class="line">            <span class="class"><span class="keyword">struct</span> <span class="title">InputStream</span> *<span class="title">ist</span> =</span> ifilter-&gt;ist;</span><br><span class="line">            <span class="comment">//1.3 释放InputFilter关联的FrameQueue(AVFifoBuffer)</span></span><br><span class="line">            <span class="keyword">while</span> (av_fifo_size(ifilter-&gt;frame_queue)) {</span><br><span class="line">                AVFrame *frame;</span><br><span class="line">                <span class="comment">//1.3.1 依次释放FrameQueue(AVFifoBuffer)中的AVFrame</span></span><br><span class="line">                av_fifo_generic_read(ifilter-&gt;frame_queue, &amp;frame,</span><br><span class="line">                                     <span class="keyword">sizeof</span>(frame), <span class="literal">NULL</span>);</span><br><span class="line">                av_frame_free(&amp;frame);</span><br><span class="line">            }</span><br><span class="line">            av_fifo_freep(&amp;ifilter-&gt;frame_queue);</span><br><span class="line">            <span class="comment">//1.2.1 释放InputStream所关联的AVSubtitle队列</span></span><br><span class="line">            <span class="keyword">if</span> (ist-&gt;sub2video.sub_queue) {</span><br><span class="line">                <span class="keyword">while</span> (av_fifo_size(ist-&gt;sub2video.sub_queue)) {</span><br><span class="line">                    AVSubtitle sub;</span><br><span class="line">                    av_fifo_generic_read(ist-&gt;sub2video.sub_queue,</span><br><span class="line">                                         &amp;sub, <span class="keyword">sizeof</span>(sub), <span class="literal">NULL</span>);</span><br><span class="line">                    avsubtitle_free(&amp;sub);</span><br><span class="line">                }</span><br><span class="line">                av_fifo_freep(&amp;ist-&gt;sub2video.sub_queue);</span><br><span class="line">            }</span><br><span class="line">            <span class="comment">//1.4 释放GPU解码的Frame Context上下文引用</span></span><br><span class="line">            av_buffer_unref(&amp;ifilter-&gt;hw_frames_ctx);</span><br><span class="line">            <span class="comment">//1.5 释放input filter name</span></span><br><span class="line">            av_freep(&amp;ifilter-&gt;name); </span><br><span class="line">            <span class="comment">//1.5 释放第j个InputFilter</span></span><br><span class="line">            av_freep(&amp;fg-&gt;inputs[j]);</span><br><span class="line">        }</span><br><span class="line">        <span class="comment">//1.6 释放所有的InputFilters的引用</span></span><br><span class="line">        av_freep(&amp;fg-&gt;inputs);</span><br><span class="line">    </span><br><span class="line">        <span class="comment">//2.1 获取所有的`OutputFilter`并释放所有属性</span></span><br><span class="line">        <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; fg-&gt;nb_outputs; j++) {</span><br><span class="line">            OutputFilter *ofilter = fg-&gt;outputs[j];</span><br><span class="line">            <span class="comment">///2.1.1 out_tmp是一个AVFilterInOut链表，处理流映射之前的临时存储</span></span><br><span class="line">            avfilter_inout_free(&amp;ofilter-&gt;out_tmp);</span><br><span class="line">            <span class="comment">///输出过滤器的额名称</span></span><br><span class="line">            av_freep(&amp;ofilter-&gt;name); </span><br><span class="line">            <span class="comment">///编码器的格式</span></span><br><span class="line">            av_freep(&amp;ofilter-&gt;formats);</span><br><span class="line">            <span class="comment">///描述音频通道具体信息，一个映射表</span></span><br><span class="line">            av_freep(&amp;ofilter-&gt;channel_layouts);</span><br><span class="line">            <span class="comment">///采样率</span></span><br><span class="line">            av_freep(&amp;ofilter-&gt;sample_rates); </span><br><span class="line">            av_freep(&amp;fg-&gt;outputs[j]);</span><br><span class="line">        }</span><br><span class="line">        av_freep(&amp;fg-&gt;outputs);</span><br><span class="line">        av_freep(&amp;fg-&gt;graph_desc);</span><br><span class="line">        <span class="comment">/// 释放 filtergraphs</span></span><br><span class="line">        av_freep(&amp;filtergraphs[i]);</span><br><span class="line">    }</span><br><span class="line">    av_freep(&amp;filtergraphs);</span><br><span class="line">    <span class="comment">///释放添加的字幕AVSubtitle</span></span><br><span class="line">    av_freep(&amp;subtitle_out);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//3. 释放输出文件</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; nb_output_files; i++) {</span><br><span class="line">        OutputFile *of = output_files[i];</span><br><span class="line">        AVFormatContext *s;</span><br><span class="line">        <span class="keyword">if</span> (!of)</span><br><span class="line">            <span class="keyword">continue</span>;</span><br><span class="line">        s = of-&gt;ctx;</span><br><span class="line">        <span class="comment">// 如果输入的是文件则需要释放文件`AVIOContext`上下文指针pb</span></span><br><span class="line">        <span class="keyword">if</span> (s &amp;&amp; s-&gt;oformat &amp;&amp; !(s-&gt;oformat-&gt;flags &amp; AVFMT_NOFILE))</span><br><span class="line">            avio_closep(&amp;s-&gt;pb);</span><br><span class="line">        <span class="comment">// 释放传入的`AVDictionary`,指针文件处理的一些属性，如是否拷贝key,value</span></span><br><span class="line">        avformat_free_context(s);</span><br><span class="line">        av_dict_free(&amp;of-&gt;opts);</span><br><span class="line"></span><br><span class="line">        av_freep(&amp;output_files[i]);</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="comment">//4. 释放 OutputStream</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; nb_output_streams; i++) {</span><br><span class="line">        OutputStream *ost = output_streams[i];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!ost)</span><br><span class="line">            <span class="keyword">continue</span>;</span><br><span class="line">        <span class="comment">//释放AVBSFContext</span></span><br><span class="line">        av_bsf_free(&amp;ost-&gt;bsf_ctx);</span><br><span class="line">        <span class="comment">//释放filtered AVFrame</span></span><br><span class="line">        av_frame_free(&amp;ost-&gt;filtered_frame);</span><br><span class="line">        <span class="comment">//last AVFrame </span></span><br><span class="line">        av_frame_free(&amp;ost-&gt;last_frame);</span><br><span class="line">        <span class="comment">//AVDictionary</span></span><br><span class="line">        av_dict_free(&amp;ost-&gt;encoder_opts);</span><br><span class="line">        <span class="comment">//forced_keyframes</span></span><br><span class="line">        av_freep(&amp;ost-&gt;forced_keyframes);</span><br><span class="line">        <span class="comment">//AVExpr,计算工具类</span></span><br><span class="line">        av_expr_free(ost-&gt;forced_keyframes_pexpr);</span><br><span class="line">        <span class="comment">//filters</span></span><br><span class="line">        av_freep(&amp;ost-&gt;avfilter);</span><br><span class="line">        av_freep(&amp;ost-&gt;logfile_prefix);</span><br><span class="line">        <span class="comment">//channel信息映射表</span></span><br><span class="line">        av_freep(&amp;ost-&gt;audio_channels_map);</span><br><span class="line">        ost-&gt;audio_channels_mapped = <span class="number">0</span>;</span><br><span class="line">        <span class="comment">//采样信息的选择项</span></span><br><span class="line">        av_dict_free(&amp;ost-&gt;sws_dict);</span><br><span class="line">        av_dict_free(&amp;ost-&gt;swr_opts);</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//编解码器上下文容器,在容器中提供了编解码器相关的输入参数,属性,原数据,如codec_type,codecid</span></span><br><span class="line">        avcodec_free_context(&amp;ost-&gt;enc_ctx);</span><br><span class="line">        <span class="comment">//与编码器选项关联的输入编解码器参数 AVCodecParameters</span></span><br><span class="line">        avcodec_parameters_free(&amp;ost-&gt;ref_par);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (ost-&gt;muxing_queue) {</span><br><span class="line">            <span class="keyword">while</span> (av_fifo_size(ost-&gt;muxing_queue)) {</span><br><span class="line">                AVPacket pkt;</span><br><span class="line">                av_fifo_generic_read(ost-&gt;muxing_queue, &amp;pkt, <span class="keyword">sizeof</span>(pkt), <span class="literal">NULL</span>);</span><br><span class="line">                av_packet_unref(&amp;pkt);</span><br><span class="line">            }</span><br><span class="line">            av_fifo_freep(&amp;ost-&gt;muxing_queue);</span><br><span class="line">        }</span><br><span class="line"></span><br><span class="line">        av_freep(&amp;output_streams[i]);</span><br><span class="line">    }</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> HAVE_THREADS</span></span><br><span class="line">    free_input_threads();</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span>  </span></span><br><span class="line">    <span class="comment">//释放全局输入文件指针</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; nb_input_files; i++) {</span><br><span class="line">        avformat_close_input(&amp;input_files[i]-&gt;ctx);</span><br><span class="line">        av_freep(&amp;input_files[i]);</span><br><span class="line">    }</span><br><span class="line">    <span class="comment">//释放全局输入流指针</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; nb_input_streams; i++) {</span><br><span class="line">        InputStream *ist = input_streams[i];</span><br><span class="line"></span><br><span class="line">        av_frame_free(&amp;ist-&gt;decoded_frame);</span><br><span class="line">        av_frame_free(&amp;ist-&gt;filter_frame);</span><br><span class="line">        av_dict_free(&amp;ist-&gt;decoder_opts);</span><br><span class="line">        avsubtitle_free(&amp;ist-&gt;prev_sub.subtitle);</span><br><span class="line">        av_frame_free(&amp;ist-&gt;sub2video.frame);</span><br><span class="line">        av_freep(&amp;ist-&gt;filters);</span><br><span class="line">        av_freep(&amp;ist-&gt;hwaccel_device);</span><br><span class="line">        av_freep(&amp;ist-&gt;dts_buffer);</span><br><span class="line"></span><br><span class="line">        avcodec_free_context(&amp;ist-&gt;dec_ctx);</span><br><span class="line"></span><br><span class="line">        av_freep(&amp;input_streams[i]);</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (vstats_file) {</span><br><span class="line">        <span class="keyword">if</span> (fclose(vstats_file))</span><br><span class="line">            av_log(<span class="literal">NULL</span>, AV_LOG_ERROR,</span><br><span class="line">                   <span class="string">"Error closing vstats file, loss of information possible: %s\n"</span>,</span><br><span class="line">                   av_err2str(AVERROR(errno)));</span><br><span class="line">    }</span><br><span class="line">    av_freep(&amp;vstats_filename);</span><br><span class="line"></span><br><span class="line">    av_freep(&amp;input_streams);</span><br><span class="line">    av_freep(&amp;input_files);</span><br><span class="line">    av_freep(&amp;output_streams);</span><br><span class="line">    av_freep(&amp;output_files);</span><br><span class="line"></span><br><span class="line">    uninit_opts();</span><br><span class="line">    <span class="comment">//这里是根据`HAVE_WINSOCK2_H`,默认没有开启</span></span><br><span class="line">    avformat_network_deinit();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (received_sigterm) {</span><br><span class="line">        av_log(<span class="literal">NULL</span>, AV_LOG_INFO, <span class="string">"Exiting normally, received signal %d.\n"</span>,</span><br><span class="line">               (<span class="keyword">int</span>) received_sigterm);</span><br><span class="line">    } <span class="keyword">else</span> <span class="keyword">if</span> (ret &amp;&amp; atomic_load(&amp;transcode_init_done)) {</span><br><span class="line">        av_log(<span class="literal">NULL</span>, AV_LOG_INFO, <span class="string">"Conversion failed!\n"</span>);</span><br><span class="line">    }</span><br><span class="line">    term_exit();</span><br><span class="line">    ffmpeg_exited = <span class="number">1</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>

<h2 id="FFmpeg-main函数-avdevice-register-all"><a href="#FFmpeg-main函数-avdevice-register-all" class="headerlink" title="FFmpeg main函数-avdevice_register_all()"></a>FFmpeg main函数-avdevice_register_all()</h2><p>在<code>avpriv_register_devices(outdev_list, indev_list);</code>注册成了输出和输出复用器(device)</p>
<figure class="highlight swift"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> const <span class="type">AVOutputFormat</span> <span class="operator">*</span> const outdev_list[] <span class="operator">=</span> {</span><br><span class="line">    <span class="operator">&amp;</span>ff_audiotoolbox_muxer,</span><br><span class="line">    <span class="type">NULL</span> };</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> const <span class="type">AVInputFormat</span> <span class="operator">*</span> const indev_list[] <span class="operator">=</span> {</span><br><span class="line">    <span class="operator">&amp;</span>ff_avfoundation_demuxer,</span><br><span class="line">    <span class="operator">&amp;</span>ff_lavfi_demuxer,</span><br><span class="line">    <span class="type">NULL</span> }；</span><br></pre></td></tr></tbody></table></figure>

<p>不同的平台可能会有不同的输入输出复用器(设备),在<code>&lt;libavdevice/alldevices.c&gt;</code>中可以找到这些默认的复用器</p>
<figure class="highlight plain"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">/* devices */ </span><br><span class="line">extern AVInputFormat  ff_android_camera_demuxer;</span><br><span class="line">extern AVOutputFormat ff_audiotoolbox_muxer;</span><br><span class="line">extern AVInputFormat  ff_avfoundation_demuxer; </span><br><span class="line">extern AVInputFormat  ff_lavfi_demuxer; </span><br><span class="line">extern AVOutputFormat ff_opengl_muxer; </span><br><span class="line">...</span><br></pre></td></tr></tbody></table></figure>
<p>在libavdevice中我们可以找到这个复用器的详细介绍,这里定义了<code>ff_audiotoolbox_muxer</code>,它的具体实现是由<code>AudioToolbox</code>框架来实现的</p>
<figure class="highlight c"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">AVOutputFormat ff_audiotoolbox_muxer = {</span><br><span class="line">    .name           = <span class="string">"audiotoolbox"</span>,</span><br><span class="line">    .long_name      = NULL_IF_CONFIG_SMALL(<span class="string">"AudioToolbox output device"</span>),</span><br><span class="line">    .priv_data_size = <span class="keyword">sizeof</span>(ATContext),</span><br><span class="line">    .audio_codec    = AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE),</span><br><span class="line">    .video_codec    = AV_CODEC_ID_NONE,</span><br><span class="line">    .write_header   = at_write_header,</span><br><span class="line">    .write_packet   = at_write_packet,</span><br><span class="line">    .write_trailer  = at_write_trailer,</span><br><span class="line">    .flags          = AVFMT_NOFILE,</span><br><span class="line">    .priv_class     = &amp;at_class,</span><br><span class="line">};</span><br><span class="line"></span><br></pre></td></tr></tbody></table></figure>

<ul>
<li>将输入输出的muxer_list通过链表链接起来</li>
</ul>
<figure class="highlight c"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">av_format_init_next</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">    AVOutputFormat *prevout = <span class="literal">NULL</span>, *out;</span><br><span class="line">    AVInputFormat *previn = <span class="literal">NULL</span>, *in;</span><br><span class="line">  </span><br><span class="line">    ff_mutex_lock(&amp;avpriv_register_devices_mutex);</span><br><span class="line">    <span class="comment">//muxer_list为全局静态变量,保存了ffmpeg的所有默认的复用器</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; (out = (AVOutputFormat*)muxer_list[i]); i++) {</span><br><span class="line">        <span class="keyword">if</span> (prevout)</span><br><span class="line">            prevout-&gt;next = out;</span><br><span class="line">        prevout = out;</span><br><span class="line">    }</span><br><span class="line">    <span class="comment">//输出设备列表</span></span><br><span class="line">    <span class="keyword">if</span> (outdev_list) {</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; (out = (AVOutputFormat*)outdev_list[i]); i++) {</span><br><span class="line">            <span class="keyword">if</span> (prevout)</span><br><span class="line">                prevout-&gt;next = out;</span><br><span class="line">            prevout = out;</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">    <span class="comment">//同上</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; (in = (AVInputFormat*)demuxer_list[i]); i++) {</span><br><span class="line">        <span class="keyword">if</span> (previn)</span><br><span class="line">            previn-&gt;next = in;</span><br><span class="line">        previn = in;</span><br><span class="line">    }</span><br><span class="line">    <span class="comment">//输入设备列表,由于是本地是通过xcode直接运行输入的</span></span><br><span class="line">    <span class="keyword">if</span> (indev_list) {</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; (in = (AVInputFormat*)indev_list[i]); i++) {</span><br><span class="line">            <span class="keyword">if</span> (previn)</span><br><span class="line">                previn-&gt;next = in;</span><br><span class="line">            previn = in;</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    ff_mutex_unlock(&amp;avpriv_register_devices_mutex);</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>

<ul>
<li><code>AVInputFormat</code>和<code>AVOuputFormat</code>通过链表进行链接</li>
</ul>
<h2 id="FFmpeg-main函数-show-banner"><a href="#FFmpeg-main函数-show-banner" class="headerlink" title="FFmpeg main函数-show_banner()"></a>FFmpeg main函数-show_banner()</h2><ul>
<li>根据传入的参数打印一些版权,版本信息,build环境信息等</li>
</ul>
<figure class="highlight c"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">show_banner</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv, <span class="keyword">const</span> OptionDef *options)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">    <span class="keyword">int</span> idx = locate_option(argc, argv, options, <span class="string">"version"</span>);</span><br><span class="line">    <span class="keyword">if</span> (hide_banner || idx)</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">    print_program_info (INDENT|SHOW_COPYRIGHT, AV_LOG_INFO);</span><br><span class="line">    print_all_libs_info(INDENT|SHOW_CONFIG,  AV_LOG_INFO);</span><br><span class="line">    print_all_libs_info(INDENT|SHOW_VERSION, AV_LOG_INFO);</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></tbody></table></figure>

<h2 id="FFmpeg-main函数-ffmpeg-parse-options"><a href="#FFmpeg-main函数-ffmpeg-parse-options" class="headerlink" title="FFmpeg main函数-ffmpeg_parse_options()"></a>FFmpeg main函数-ffmpeg_parse_options()</h2><ul>
<li>对传入的参数进行分组表示,前面提到了ffmpeg的命令基本用法,和group对象的结构完全对应</li>
</ul>
<figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...</span><br></pre></td></tr></tbody></table></figure>

<ul>
<li>OptionGroup定义如下：</li>
</ul>
<figure class="highlight c"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">OptionGroup</span> {</span></span><br><span class="line">    <span class="keyword">const</span> OptionGroupDef *group_def;</span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">char</span> *arg;</span><br><span class="line"></span><br><span class="line">    Option *opts; <span class="comment">//全局类型的参数</span></span><br><span class="line">    <span class="keyword">int</span>  nb_opts;</span><br><span class="line"></span><br><span class="line">    AVDictionary *codec_opts;       <span class="comment">//编解码器相关的选项参数</span></span><br><span class="line">    AVDictionary *format_opts;      <span class="comment">//解复用和复用相关的参数</span></span><br><span class="line">    AVDictionary *resample_opts;    <span class="comment">//重采样相关的参数</span></span><br><span class="line">    AVDictionary *sws_dict;         <span class="comment">//swscale中执行的参数</span></span><br><span class="line">    AVDictionary *swr_opts;         <span class="comment">//swresample options</span></span><br><span class="line">} OptionGroup;</span><br></pre></td></tr></tbody></table></figure>


<figure class="highlight c"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">ffmpeg_parse_options</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">    typedef struct OptionParseContext {</span></span><br><span class="line"><span class="comment">        OptionGroup global_opts;</span></span><br><span class="line"><span class="comment">        OptionGroupList *groups;</span></span><br><span class="line"><span class="comment">        int           nb_groups; </span></span><br><span class="line"><span class="comment">        OptionGroup cur_group;</span></span><br><span class="line"><span class="comment">    } OptionParseContext;</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="comment">//对传入的参数进行分组</span></span><br><span class="line">    OptionParseContext octx;</span><br><span class="line">    <span class="keyword">uint8_t</span> error[<span class="number">128</span>];</span><br><span class="line">    <span class="keyword">int</span> ret;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">memset</span>(&amp;octx, <span class="number">0</span>, <span class="keyword">sizeof</span>(octx));</span><br><span class="line"></span><br><span class="line">    <span class="comment">//参数分组</span></span><br><span class="line">    ret = split_commandline(&amp;octx, argc, argv, options, groups,</span><br><span class="line">                            FF_ARRAY_ELEMS(groups));</span><br><span class="line">    <span class="keyword">if</span> (ret &lt; <span class="number">0</span>) {</span><br><span class="line">        av_log(<span class="literal">NULL</span>, AV_LOG_FATAL, <span class="string">"Error splitting the argument list: "</span>);</span><br><span class="line">        <span class="keyword">goto</span> fail;</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="comment">//global参数应用</span></span><br><span class="line">    ret = parse_optgroup(<span class="literal">NULL</span>, &amp;octx.global_opts);</span><br><span class="line">    <span class="keyword">if</span> (ret &lt; <span class="number">0</span>) {</span><br><span class="line">        av_log(<span class="literal">NULL</span>, AV_LOG_FATAL, <span class="string">"Error parsing global options: "</span>);</span><br><span class="line">        <span class="keyword">goto</span> fail;</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* configure terminal and setup signal handlers */</span></span><br><span class="line">    term_init();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* open input files */</span></span><br><span class="line">    ret = open_files(&amp;octx.groups[GROUP_INFILE], <span class="string">"input"</span>, open_input_file);</span><br><span class="line">    <span class="keyword">if</span> (ret &lt; <span class="number">0</span>) {</span><br><span class="line">        av_log(<span class="literal">NULL</span>, AV_LOG_FATAL, <span class="string">"Error opening input files: "</span>);</span><br><span class="line">        <span class="keyword">goto</span> fail;</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="comment">//创建filtergraphs,滤镜特效相关</span></span><br><span class="line">    ret = init_complex_filters();</span><br><span class="line">    <span class="keyword">if</span> (ret &lt; <span class="number">0</span>) {</span><br><span class="line">        av_log(<span class="literal">NULL</span>, AV_LOG_FATAL, <span class="string">"Error initializing complex filters.\n"</span>);</span><br><span class="line">        <span class="keyword">goto</span> fail;</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* open output files */</span></span><br><span class="line">    ret = open_files(&amp;octx.groups[GROUP_OUTFILE], <span class="string">"output"</span>, open_output_file);</span><br><span class="line">    <span class="keyword">if</span> (ret &lt; <span class="number">0</span>) {</span><br><span class="line">        av_log(<span class="literal">NULL</span>, AV_LOG_FATAL, <span class="string">"Error opening output files: "</span>);</span><br><span class="line">        <span class="keyword">goto</span> fail;</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    check_filter_outputs();</span><br><span class="line"></span><br><span class="line">fail:</span><br><span class="line">    uninit_parse_context(&amp;octx);</span><br><span class="line">    <span class="keyword">if</span> (ret &lt; <span class="number">0</span>) {</span><br><span class="line">        av_strerror(ret, error, <span class="keyword">sizeof</span>(error));</span><br><span class="line">        av_log(<span class="literal">NULL</span>, AV_LOG_FATAL, <span class="string">"%s\n"</span>, error);</span><br><span class="line">    }</span><br><span class="line">    <span class="keyword">return</span> ret;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>

<h2 id="FFmpeg-main函数-transcode"><a href="#FFmpeg-main函数-transcode" class="headerlink" title="FFmpeg main函数-transcode()"></a>FFmpeg main函数-transcode()</h2><p>当输入输出参数解析完毕,并且设置好输入输出文件之后执行这个方法,来处理输入文件</p>
<figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br></pre></td><td class="code"><pre><span class="line">static int transcode(void)</span><br><span class="line">{  </span><br><span class="line">    //1.定义输入输出文件的本地变量，用于从ffmpeg的全局环境变量中读取参数</span><br><span class="line">    int ret, i;</span><br><span class="line">    AVFormatContext *os;</span><br><span class="line">    OutputStream *ost;</span><br><span class="line">    InputStream *ist;</span><br><span class="line">    int64_t timer_start;</span><br><span class="line">    int64_t total_packets_written = 0;</span><br><span class="line">    </span><br><span class="line">    //2. 创建滤波器，初始化输入输出流,encoder,写入文件头部信息等..见下文</span><br><span class="line">    ret = transcode_init();</span><br><span class="line">    if (ret &lt; 0)</span><br><span class="line">        goto fail;</span><br><span class="line"></span><br><span class="line">    //3. 处理终端交互命令,如yes/no选项</span><br><span class="line">    while (!received_sigterm) </span><br><span class="line">    ...</span><br><span class="line">     </span><br><span class="line">    //4. 将解包的数据传入到`InputStream`中,并根据配置参数选项对每一帧AVFrame进编解码操作,见下文</span><br><span class="line">    for (i = 0; i &lt; nb_input_streams; i++) {</span><br><span class="line">        ist = input_streams[i];</span><br><span class="line">        if (!input_files[ist-&gt;file_index]-&gt;eof_reached) {</span><br><span class="line">            process_input_packet(ist, NULL, 0);</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    flush_encoders();</span><br><span class="line"></span><br><span class="line">    term_exit();</span><br><span class="line"></span><br><span class="line">    /* write the trailer if needed and close file */</span><br><span class="line">    for (i = 0; i &lt; nb_output_files; i++) {</span><br><span class="line">        os = output_files[i]-&gt;ctx;</span><br><span class="line">        if (!output_files[i]-&gt;header_written) {</span><br><span class="line">            av_log(NULL, AV_LOG_ERROR,</span><br><span class="line">                   "Nothing was written into output file %d (%s), because "</span><br><span class="line">                   "at least one of its streams received no packets.\n",</span><br><span class="line">                   i, os-&gt;url);</span><br><span class="line">            continue;</span><br><span class="line">        }</span><br><span class="line">        if ((ret = av_write_trailer(os)) &lt; 0) {</span><br><span class="line">            av_log(NULL, AV_LOG_ERROR, "Error writing trailer of %s: %s\n", os-&gt;url, av_err2str(ret));</span><br><span class="line">            if (exit_on_error)</span><br><span class="line">                exit_program(1);</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    /* dump report by using the first video and audio streams */</span><br><span class="line">    print_report(1, timer_start, av_gettime_relative());</span><br><span class="line"></span><br><span class="line">    /* close each encoder */</span><br><span class="line">    for (i = 0; i &lt; nb_output_streams; i++) {</span><br><span class="line">        ost = output_streams[i];</span><br><span class="line">        if (ost-&gt;encoding_needed) {</span><br><span class="line">            av_freep(&amp;ost-&gt;enc_ctx-&gt;stats_in);</span><br><span class="line">        }</span><br><span class="line">        total_packets_written += ost-&gt;packets_written;</span><br><span class="line">        if (!ost-&gt;packets_written &amp;&amp; (abort_on_flags &amp; ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM)) {</span><br><span class="line">            av_log(NULL, AV_LOG_FATAL, "Empty output on stream %d.\n", i);</span><br><span class="line">            exit_program(1);</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    if (!total_packets_written &amp;&amp; (abort_on_flags &amp; ABORT_ON_FLAG_EMPTY_OUTPUT)) {</span><br><span class="line">        av_log(NULL, AV_LOG_FATAL, "Empty output\n");</span><br><span class="line">        exit_program(1);</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    for (i = 0; i &lt; nb_input_streams; i++) {</span><br><span class="line">        ist = input_streams[i];</span><br><span class="line">        if (ist-&gt;decoding_needed) {</span><br><span class="line">            avcodec_close(ist-&gt;dec_ctx);</span><br><span class="line">            if (ist-&gt;hwaccel_uninit)</span><br><span class="line">                ist-&gt;hwaccel_uninit(ist-&gt;dec_ctx);</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    hw_device_free_all();</span><br><span class="line"></span><br><span class="line">    /* finished ! */</span><br><span class="line">    ret = 0;</span><br><span class="line"></span><br><span class="line"> fail:</span><br><span class="line"> ...</span><br><span class="line">    if (output_streams) {</span><br><span class="line">        for (i = 0; i &lt; nb_output_streams; i++) {</span><br><span class="line">            ost = output_streams[i];</span><br><span class="line">            if (ost) {</span><br><span class="line">                if (ost-&gt;logfile) {</span><br><span class="line">                    if (fclose(ost-&gt;logfile))</span><br><span class="line">                        av_log(NULL, AV_LOG_ERROR,</span><br><span class="line">                               "Error closing logfile, loss of information possible: %s\n",</span><br><span class="line">                               av_err2str(AVERROR(errno)));</span><br><span class="line">                    ost-&gt;logfile = NULL;</span><br><span class="line">                }</span><br><span class="line">                av_freep(&amp;ost-&gt;forced_kf_pts);</span><br><span class="line">                av_freep(&amp;ost-&gt;apad);</span><br><span class="line">                av_freep(&amp;ost-&gt;disposition);</span><br><span class="line">                av_dict_free(&amp;ost-&gt;encoder_opts);</span><br><span class="line">                av_dict_free(&amp;ost-&gt;sws_dict);</span><br><span class="line">                av_dict_free(&amp;ost-&gt;swr_opts);</span><br><span class="line">                av_dict_free(&amp;ost-&gt;resample_opts);</span><br><span class="line">            }</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">    return ret;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>

<h3 id="transcode-init"><a href="#transcode-init" class="headerlink" title="transcode_init()"></a>transcode_init()</h3><figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">static int transcode_init(void)</span><br><span class="line">{   </span><br><span class="line">    //1.转码环境变量初始化</span><br><span class="line">    int ret = 0, i, j, k;</span><br><span class="line">    //转码容器上下文初始化</span><br><span class="line">    AVFormatContext *oc; </span><br><span class="line">    //用于转换文件到流映射</span><br><span class="line">    OutputStream *ost;</span><br><span class="line">    InputStream *ist;</span><br><span class="line">    char error[1024] = {0};</span><br><span class="line">    </span><br><span class="line">    //2.创建滤波器如果存可用的滤波器,FFmpeg的main函数中注册默认的滤波器,只有在打开输出文件的时候创建一个空滤波器。 此处只有一个滤波器，ffmpeg_parse_options-》open_files-》open_output_file-》init_simple_filtergraph，用来保存filter的上下文参数.</span><br><span class="line">    for (i = 0; i &lt; nb_filtergraphs; i++) {</span><br><span class="line">        FilterGraph *fg = filtergraphs[i];</span><br><span class="line">        for (j = 0; j &lt; fg-&gt;nb_outputs; j++) {</span><br><span class="line">            OutputFilter *ofilter = fg-&gt;outputs[j];</span><br><span class="line">            if (!ofilter-&gt;ost || ofilter-&gt;ost-&gt;source_index &gt;= 0)</span><br><span class="line">                continue;</span><br><span class="line">            if (fg-&gt;nb_inputs != 1)</span><br><span class="line">                continue;</span><br><span class="line">            for (k = nb_input_streams-1; k &gt;= 0 ; k--)</span><br><span class="line">                if (fg-&gt;inputs[0]-&gt;ist == input_streams[k])</span><br><span class="line">                    break;</span><br><span class="line">            ofilter-&gt;ost-&gt;source_index = k;</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    //3.初始化帧速率仿真</span><br><span class="line">    for (i = 0; i &lt; nb_input_files; i++) {</span><br><span class="line">        InputFile *ifile = input_files[i];</span><br><span class="line">        if (ifile-&gt;rate_emu)</span><br><span class="line">            for (j = 0; j &lt; ifile-&gt;nb_streams; j++)</span><br><span class="line">                input_streams[j + ifile-&gt;ist_index]-&gt;start = av_gettime_relative();</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    //4.初始化输入流</span><br><span class="line">    for (i = 0; i &lt; nb_input_streams; i++)</span><br><span class="line">        if ((ret = init_input_stream(i, error, sizeof(error))) &lt; 0) {</span><br><span class="line">            for (i = 0; i &lt; nb_output_streams; i++) {</span><br><span class="line">                ost = output_streams[i];</span><br><span class="line">                avcodec_close(ost-&gt;enc_ctx);</span><br><span class="line">            }</span><br><span class="line">            goto dump_format;</span><br><span class="line">        }</span><br><span class="line">    //5.打开输出流的编码器</span><br><span class="line">    /* open each encoder */</span><br><span class="line">    for (i = 0; i &lt; nb_output_streams; i++) {</span><br><span class="line">        // skip streams fed from filtergraphs until we have a frame for them</span><br><span class="line">        if (output_streams[i]-&gt;filter)</span><br><span class="line">            continue;</span><br><span class="line"></span><br><span class="line">        ret = init_output_stream(output_streams[i], error, sizeof(error));</span><br><span class="line">        if (ret &lt; 0)</span><br><span class="line">            goto dump_format;</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    /* discard unused programs */</span><br><span class="line">    for (i = 0; i &lt; nb_input_files; i++) {</span><br><span class="line">        InputFile *ifile = input_files[i];</span><br><span class="line">        for (j = 0; j &lt; ifile-&gt;ctx-&gt;nb_programs; j++) {</span><br><span class="line">            AVProgram *p = ifile-&gt;ctx-&gt;programs[j];</span><br><span class="line">            int discard  = AVDISCARD_ALL;</span><br><span class="line"></span><br><span class="line">            for (k = 0; k &lt; p-&gt;nb_stream_indexes; k++)</span><br><span class="line">                if (!input_streams[ifile-&gt;ist_index + p-&gt;stream_index[k]]-&gt;discard) {</span><br><span class="line">                    discard = AVDISCARD_DEFAULT;</span><br><span class="line">                    break;</span><br><span class="line">                }</span><br><span class="line">            p-&gt;discard = discard;</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">    //6. 将header信息写入文件,</span><br><span class="line"><span class="meta">#</span><span class="bash">        - 当没有stream时直接执行check_init_output_file</span></span><br><span class="line"><span class="meta">#</span><span class="bash">        - 然后调用了 avformat_write_header(of-&gt;ctx, &amp;of-&gt;opts); of: OuputFile</span></span><br><span class="line"><span class="meta">#</span><span class="bash">        - 然后执行 int (*write_header)(struct AVFormatContext *);</span></span><br><span class="line"><span class="meta">#</span><span class="bash">        - 然后执行对应平台当前指定的复用器,`write_header`,将header信息写入文件</span></span><br><span class="line"><span class="meta">#</span><span class="bash">     AVOutputFormat ff_ilbc_muxer = {</span></span><br><span class="line"><span class="meta">#</span><span class="bash">     .name         = <span class="string">"ilbc"</span>,</span></span><br><span class="line"><span class="meta">#</span><span class="bash">     .long_name    = NULL_IF_CONFIG_SMALL(<span class="string">"iLBC storage"</span>),</span></span><br><span class="line"><span class="meta">#</span><span class="bash">     .mime_type    = <span class="string">"audio/iLBC"</span>,</span></span><br><span class="line"><span class="meta">#</span><span class="bash">     .extensions   = <span class="string">"lbc"</span>,</span></span><br><span class="line"><span class="meta">#</span><span class="bash">     .audio_codec  = AV_CODEC_ID_ILBC,</span></span><br><span class="line"><span class="meta">#</span><span class="bash">     .write_header = ilbc_write_header,</span></span><br><span class="line"><span class="meta">#</span><span class="bash">     .write_packet = ff_raw_write_packet,</span></span><br><span class="line"><span class="meta">#</span><span class="bash">     .flags        = AVFMT_NOTIMESTAMPS,</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> };</span></span><br><span class="line">    /* write headers for files with no streams */</span><br><span class="line">    for (i = 0; i &lt; nb_output_files; i++) {</span><br><span class="line">        oc = output_files[i]-&gt;ctx;</span><br><span class="line">        if (oc-&gt;oformat-&gt;flags &amp; AVFMT_NOSTREAMS &amp;&amp; oc-&gt;nb_streams == 0) {</span><br><span class="line">            ret = check_init_output_file(output_files[i], i);</span><br><span class="line">            if (ret &lt; 0)</span><br><span class="line">                goto dump_format;</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    //7.查看stream所关联的滤波器的信息</span><br><span class="line">    av_log(NULL, AV_LOG_INFO, "Stream mapping:\n");</span><br><span class="line">    for (i = 0; i &lt; nb_input_streams; i++) {</span><br><span class="line">        ist = input_streams[i];</span><br><span class="line"></span><br><span class="line">        for (j = 0; j &lt; ist-&gt;nb_filters; j++) {</span><br><span class="line">            //查看stream所关联的滤波器的信息</span><br><span class="line">            if (!filtergraph_is_simple(ist-&gt;filters[j]-&gt;graph)) {</span><br><span class="line">                av_log(NULL, AV_LOG_INFO, "  Stream #%d:%d (%s) -&gt; %s",</span><br><span class="line">                       ist-&gt;file_index, ist-&gt;st-&gt;index, ist-&gt;dec ? ist-&gt;dec-&gt;name : "?",</span><br><span class="line">                       ist-&gt;filters[j]-&gt;name);</span><br><span class="line">                if (nb_filtergraphs &gt; 1)</span><br><span class="line">                    av_log(NULL, AV_LOG_INFO, " (graph %d)", ist-&gt;filters[j]-&gt;graph-&gt;index);</span><br><span class="line">                av_log(NULL, AV_LOG_INFO, "\n");</span><br><span class="line">            }</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">    //8. 初始化本地变量outputStream,打印输出</span><br><span class="line">    for (i = 0; i &lt; nb_output_streams; i++) {</span><br><span class="line">        ost = output_streams[i];</span><br><span class="line"></span><br><span class="line">        if (ost-&gt;attachment_filename) {</span><br><span class="line">            /* an attached file */</span><br><span class="line">            av_log(NULL, AV_LOG_INFO, "  File %s -&gt; Stream #%d:%d\n",</span><br><span class="line">                   ost-&gt;attachment_filename, ost-&gt;file_index, ost-&gt;index);</span><br><span class="line">            continue;</span><br><span class="line">        }</span><br><span class="line"></span><br><span class="line">        if (ost-&gt;filter &amp;&amp; !filtergraph_is_simple(ost-&gt;filter-&gt;graph)) {</span><br><span class="line">            /* output from a complex graph */</span><br><span class="line">            av_log(NULL, AV_LOG_INFO, "  %s", ost-&gt;filter-&gt;name);</span><br><span class="line">            if (nb_filtergraphs &gt; 1)</span><br><span class="line">                av_log(NULL, AV_LOG_INFO, " (graph %d)", ost-&gt;filter-&gt;graph-&gt;index);</span><br><span class="line"></span><br><span class="line">            av_log(NULL, AV_LOG_INFO, " -&gt; Stream #%d:%d (%s)\n", ost-&gt;file_index,</span><br><span class="line">                   ost-&gt;index, ost-&gt;enc ? ost-&gt;enc-&gt;name : "?");</span><br><span class="line">            continue;</span><br><span class="line">        }</span><br><span class="line"></span><br><span class="line">        av_log(NULL, AV_LOG_INFO, "  Stream #%d:%d -&gt; #%d:%d",</span><br><span class="line">               input_streams[ost-&gt;source_index]-&gt;file_index,</span><br><span class="line">               input_streams[ost-&gt;source_index]-&gt;st-&gt;index,</span><br><span class="line">               ost-&gt;file_index,</span><br><span class="line">               ost-&gt;index);</span><br><span class="line">        if (ost-&gt;sync_ist != input_streams[ost-&gt;source_index])</span><br><span class="line">            av_log(NULL, AV_LOG_INFO, " [sync #%d:%d]",</span><br><span class="line">                   ost-&gt;sync_ist-&gt;file_index,</span><br><span class="line">                   ost-&gt;sync_ist-&gt;st-&gt;index);</span><br><span class="line">        if (ost-&gt;stream_copy)</span><br><span class="line">            av_log(NULL, AV_LOG_INFO, " (copy)");</span><br><span class="line">        else {</span><br><span class="line">            const AVCodec *in_codec    = input_streams[ost-&gt;source_index]-&gt;dec;</span><br><span class="line">            const AVCodec *out_codec   = ost-&gt;enc;</span><br><span class="line">            const char *decoder_name   = "?";</span><br><span class="line">            const char *in_codec_name  = "?";</span><br><span class="line">            const char *encoder_name   = "?";</span><br><span class="line">            const char *out_codec_name = "?";</span><br><span class="line">            const AVCodecDescriptor *desc;</span><br><span class="line"></span><br><span class="line">            if (in_codec) {</span><br><span class="line">                decoder_name  = in_codec-&gt;name;</span><br><span class="line">                desc = avcodec_descriptor_get(in_codec-&gt;id);</span><br><span class="line">                if (desc)</span><br><span class="line">                    in_codec_name = desc-&gt;name;</span><br><span class="line">                if (!strcmp(decoder_name, in_codec_name))</span><br><span class="line">                    decoder_name = "native";</span><br><span class="line">            }</span><br><span class="line"></span><br><span class="line">            if (out_codec) {</span><br><span class="line">                encoder_name   = out_codec-&gt;name;</span><br><span class="line">                desc = avcodec_descriptor_get(out_codec-&gt;id);</span><br><span class="line">                if (desc)</span><br><span class="line">                    out_codec_name = desc-&gt;name;</span><br><span class="line">                if (!strcmp(encoder_name, out_codec_name))</span><br><span class="line">                    encoder_name = "native";</span><br><span class="line">            }</span><br><span class="line"></span><br><span class="line">            av_log(NULL, AV_LOG_INFO, " (%s (%s) -&gt; %s (%s))",</span><br><span class="line">                   in_codec_name, decoder_name,</span><br><span class="line">                   out_codec_name, encoder_name);</span><br><span class="line">        }</span><br><span class="line">        av_log(NULL, AV_LOG_INFO, "\n");</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    if (ret) {</span><br><span class="line">        av_log(NULL, AV_LOG_ERROR, "%s\n", error);</span><br><span class="line">        return ret;</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    atomic_store(&amp;transcode_init_done, 1);</span><br><span class="line"></span><br><span class="line">    return 0;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>

<h3 id="process-input-packet"><a href="#process-input-packet" class="headerlink" title="process_input_packet"></a>process_input_packet</h3><p>特别注意,在处理完解包传入的AVPacket之后需要清除缓冲区的数</p>
<figure class="highlight c"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">process_input_packet</span><span class="params">(InputStream *ist, <span class="keyword">const</span> AVPacket *pkt, <span class="keyword">int</span> no_eof)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line">    <span class="keyword">int</span> ret = <span class="number">0</span>, i;</span><br><span class="line">    <span class="keyword">int</span> repeating = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">int</span> eof_reached = <span class="number">0</span>;</span><br><span class="line">    ...</span><br><span class="line">    <span class="comment">//1. 解码</span></span><br><span class="line">    <span class="keyword">while</span> (ist-&gt;decoding_needed) {  </span><br><span class="line">        ....</span><br><span class="line">        <span class="keyword">switch</span> (ist-&gt;dec_ctx-&gt;codec_type) {</span><br><span class="line">        <span class="keyword">case</span> AVMEDIA_TYPE_AUDIO:</span><br><span class="line">            ret = decode_audio    (ist, repeating ? <span class="literal">NULL</span> : &amp;avpkt, &amp;got_output,</span><br><span class="line">                                   &amp;decode_failed);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> AVMEDIA_TYPE_VIDEO:</span><br><span class="line">            ret = decode_video    (ist, repeating ? <span class="literal">NULL</span> : &amp;avpkt, &amp;got_output, &amp;duration_pts, !pkt,</span><br><span class="line">                                   &amp;decode_failed);</span><br><span class="line">            <span class="keyword">if</span> (!repeating || !pkt || got_output) {</span><br><span class="line">                <span class="keyword">if</span> (pkt &amp;&amp; pkt-&gt;duration) {</span><br><span class="line">                    duration_dts = av_rescale_q(pkt-&gt;duration, ist-&gt;st-&gt;time_base, AV_TIME_BASE_Q);</span><br><span class="line">                } <span class="keyword">else</span> <span class="keyword">if</span>(ist-&gt;dec_ctx-&gt;framerate.num != <span class="number">0</span> &amp;&amp; ist-&gt;dec_ctx-&gt;framerate.den != <span class="number">0</span>) {</span><br><span class="line">                    <span class="keyword">int</span> ticks= av_stream_get_parser(ist-&gt;st) ? av_stream_get_parser(ist-&gt;st)-&gt;repeat_pict+<span class="number">1</span> : ist-&gt;dec_ctx-&gt;ticks_per_frame;</span><br><span class="line">                    duration_dts = ((<span class="keyword">int64_t</span>)AV_TIME_BASE *</span><br><span class="line">                                    ist-&gt;dec_ctx-&gt;framerate.den * ticks) /</span><br><span class="line">                                    ist-&gt;dec_ctx-&gt;framerate.num / ist-&gt;dec_ctx-&gt;ticks_per_frame;</span><br><span class="line">                }</span><br><span class="line">                <span class="keyword">if</span>(ist-&gt;dts != AV_NOPTS_VALUE &amp;&amp; duration_dts) {</span><br><span class="line">                    ist-&gt;next_dts += duration_dts;</span><br><span class="line">                }<span class="keyword">else</span></span><br><span class="line">                    ist-&gt;next_dts = AV_NOPTS_VALUE;</span><br><span class="line">            }</span><br><span class="line">            <span class="keyword">if</span> (got_output) {</span><br><span class="line">                <span class="keyword">if</span> (duration_pts &gt; <span class="number">0</span>) {</span><br><span class="line">                    ist-&gt;next_pts += av_rescale_q(duration_pts, ist-&gt;st-&gt;time_base, AV_TIME_BASE_Q);</span><br><span class="line">                } <span class="keyword">else</span> {</span><br><span class="line">                    ist-&gt;next_pts += duration_dts;</span><br><span class="line">                }</span><br><span class="line">            }</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> AVMEDIA_TYPE_SUBTITLE:</span><br><span class="line">            <span class="keyword">if</span> (repeating)</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            ret = transcode_subtitles(ist, &amp;avpkt, &amp;got_output, &amp;decode_failed);</span><br><span class="line">            <span class="keyword">if</span> (!pkt &amp;&amp; ret &gt;= <span class="number">0</span>)</span><br><span class="line">                ret = AVERROR_EOF;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">default</span>:</span><br><span class="line">            <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">        }</span><br><span class="line">    ...</span><br><span class="line">    <span class="comment">//2. 直接拷贝stream</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; nb_output_streams; i++) {</span><br><span class="line">        OutputStream *ost = output_streams[i];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!check_output_constraints(ist, ost) || ost-&gt;encoding_needed)</span><br><span class="line">            <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line">        do_streamcopy(ist, ost, pkt);</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> !eof_reached;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>


<h2 id="FFmpeg-example本地调试"><a href="#FFmpeg-example本地调试" class="headerlink" title="FFmpeg-example本地调试"></a>FFmpeg-example本地调试</h2><p>exmaple文件在ffmpeg仓库<code>doc/</code>文件夹下的<code>examples</code>,目录如下</p>
<figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">avio_reading.c         //读取音视频文件信息</span><br><span class="line">decode_audio.c         //音频解码</span><br><span class="line">decode_video.c         //视频解码</span><br><span class="line">demuxing_decoding.c    //解复用器处理音视频</span><br><span class="line">encode_audio.c         //音频编码</span><br><span class="line">encode_video.c         //视频编码</span><br><span class="line">ffhash.c               //hash校验</span><br><span class="line">filter_audio.c         //音频处理</span><br><span class="line">filtering_audio.c      //音频处理</span><br><span class="line">filtering_video.c      //用于解码和滤波的API示例</span><br><span class="line">http_multiclient.c     //供一个文件，而不需要通过http对其进行解码或解组,流媒体传输</span><br><span class="line">hw_decode.c            //展示了如何用输出进行硬件加速解码</span><br><span class="line">metadata.c             //演示如何在应用程序中使用元数据API。</span><br><span class="line">muxing.c               //以任何支持的libavformat格式输出媒体文件。默认值使用编解码器。</span><br><span class="line">qsvdec.c               //演示如何使用输出进行QSV加速H.264解码GPU视频表面中的帧。</span><br><span class="line">remuxing.c             //解复用和合复用相关的例子</span><br><span class="line">resampling_audio.c     //音频重采样</span><br><span class="line">scaling_video.c        //视频画面比例缩放相关的示例子</span><br><span class="line">transcode_aac.c        //使用FFmpeg将输入音频文件转换为MP4容器中的AAC。</span><br><span class="line">transcoding.c          //解组、解码、滤波、编码和muxing示例</span><br><span class="line">vaapi_encode.c         //视频加速API（视频编码）编码示例</span><br><span class="line">vaapi_transcode.c      //视频加速API（视频转码）转码示例</span><br></pre></td></tr></tbody></table></figure>

<p>可以通过每个文件的<code>main</code>函数以及对传入<code>args</code>的断言介绍,去测试这些examples<br>按照<code>doc/examples/README</code>的介绍安装<code>pkg-config</code>(头文件自动搜索工具),然后在<code>FFmpeg</code>源代码的根目录执行<code>make</code>命令，就会自动编译好这些example工程，</p>
<figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">... examples % tree -L 1 </span><br><span class="line">...</span><br><span class="line">├── avio_list_dir</span><br><span class="line">├── avio_list_dir.c</span><br><span class="line">├── avio_list_dir.d</span><br><span class="line">├── avio_list_dir.o</span><br><span class="line">├── avio_list_dir.g</span><br></pre></td></tr></tbody></table></figure>

<p>这里列出了<code>vido</code>中的文件属性,也可以在去修改<code>av_log</code>函数中的内容,其中的<code>.g</code>文件相比<code>avio_list_dir</code>可以用于我们本地断点调试源文件</p>
<figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">... examples % ./avio_list_dir video </span><br><span class="line">TYPE              SIZE                           NAME   UID(GID) UGO         MODIFIED         ACCESSED   STATUS_CHANGED</span><br><span class="line">&lt;FILE&gt;         6752987                      input.mov    501(20) 644 1615644790000000 1615830067000000 1615823569000000</span><br></pre></td></tr></tbody></table></figure>

<p>参照<code>ffmpeg_g</code>的调试步骤可以很方便的研究example中的实例</p>
<h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>FFmpeg源代码中简写单词特别多,很多都没有注释,需要结合上下文语句和音视频编解码来理解</p>
<h2 id="参考连接"><a href="#参考连接" class="headerlink" title="参考连接"></a>参考连接</h2><p><a target="_blank" rel="noopener" href="https://ffmpeg.org/documentation.html">ffmpeg.org</a><br><a target="_blank" rel="noopener" href="http://slhck.info/ffmpeg-encoding-course/#/9">ffmpeg-encoding-course</a></p>

                
            </div>
            <hr/>

            

    <div class="reprint" id="reprint-statement">
        
            <div class="reprint__author">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-user">
                        jiodg45:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="/jiodg45/about" rel="external nofollow noreferrer">Longxiang.guo</a>
                </span>
            </div>
            <div class="reprint__type">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-link">
                        文章链接:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="https://jiodg45.gitee.io/jiodg45/jiodg45/2021/03/11/audio-visual/ffmpeg-4/">https://jiodg45.gitee.io/jiodg45/jiodg45/2021/03/11/audio-visual/ffmpeg-4/</a>
                </span>
            </div>
            <div class="reprint__notice">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-copyright">
                        版权声明:
                    </i>
                </span>
                <span class="reprint-info">
                    本博客所有文章除特別声明外，均采用
                    <a href="https://creativecommons.org/licenses/by/4.0/deed.zh" rel="external nofollow noreferrer" target="_blank">CC BY 4.0</a>
                    许可协议。转载请注明来源
                    <a href="/jiodg45/about" target="_blank">Longxiang.guo</a>
                    !
                </span>
            </div>
        
    </div>

    <script async defer>
      document.addEventListener("copy", function (e) {
        let toastHTML = '<span>复制成功，请遵循本文的转载规则</span><button class="btn-flat toast-action" onclick="navToReprintStatement()" style="font-size: smaller">查看</a>';
        M.toast({html: toastHTML})
      });

      function navToReprintStatement() {
        $("html, body").animate({scrollTop: $("#reprint-statement").offset().top - 80}, 800);
      }
    </script>



            <div class="tag_share" style="display: block;">
                <div class="post-meta__tag-list" style="display: inline-block;">
                    
                        <div class="article-tag">
                            
                                <a href="/jiodg45/tags/audio/">
                                    <span class="chip bg-color">audio</span>
                                </a>
                            
                                <a href="/jiodg45/tags/ffmpeg/">
                                    <span class="chip bg-color">ffmpeg</span>
                                </a>
                            
                        </div>
                    
                </div>
                <div class="post_share" style="zoom: 80%; width: fit-content; display: inline-block; float: right; margin: -0.15rem 0;">
                    <link rel="stylesheet" type="text/css" href="/jiodg45/libs/share/css/share.min.css">
<div id="article-share">

    
    <div class="social-share" data-sites="twitter,facebook,google,qq,qzone,wechat,weibo,douban,linkedin" data-wechat-qrcode-helper="<p>微信扫一扫即可分享！</p>"></div>
    <script src="/jiodg45/libs/share/js/social-share.min.js"></script>
    

    

</div>

                </div>
            </div>
            
        </div>
    </div>

    

    

    

    

    

    

    

    

    

<article id="prenext-posts" class="prev-next articles">
    <div class="row article-row">
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge left-badge text-color">
                <i class="fas fa-chevron-left"></i>&nbsp;上一篇</div>
            <div class="card">
                <a href="/jiodg45/2021/03/11/ios/ios-release-notes/">
                    <div class="card-image">
                        
                        
                        <img src="/jiodg45/medias/featureimages/12.jpg" class="responsive-img" alt="Swift新技术">
                        
                        <span class="card-title">Swift新技术</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            iOS自动化构建相关命令集合
                        
                    </div>
                    <div class="publish-info">
                        <span class="publish-date">
                            <i class="far fa-clock fa-fw icon-date"></i>2021-03-11
                        </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/jiodg45/categories/ios/" class="post-category">
                                    ios
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/jiodg45/tags/iOS-%E8%87%AA%E5%8A%A8%E5%8C%96/">
                        <span class="chip bg-color">iOS,自动化</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge right-badge text-color">
                下一篇&nbsp;<i class="fas fa-chevron-right"></i>
            </div>
            <div class="card">
                <a href="/jiodg45/2021/03/11/ios/blog-star/">
                    <div class="card-image">
                        
                        
                        <img src="/jiodg45/medias/featureimages/6.jpg" class="responsive-img" alt="知识专题收集">
                        
                        <span class="card-title">知识专题收集</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            bluetooth
                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2021-03-11
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/jiodg45/categories/ios/" class="post-category">
                                    ios
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/jiodg45/tags/iOS-bluetooth/">
                        <span class="chip bg-color">iOS,bluetooth</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
    </div>
</article>

</div>



<!-- 代码块功能依赖 -->
<script type="text/javascript" src="/jiodg45/libs/codeBlock/codeBlockFuction.js"></script>

<!-- 代码语言 -->

<script type="text/javascript" src="/jiodg45/libs/codeBlock/codeLang.js"></script>


<!-- 代码块复制 -->

<script type="text/javascript" src="/jiodg45/libs/codeBlock/codeCopy.js"></script>


<!-- 代码块收缩 -->

<script type="text/javascript" src="/jiodg45/libs/codeBlock/codeShrink.js"></script>


    </div>
    <div id="toc-aside" class="expanded col l3 hide-on-med-and-down">
        <div class="toc-widget card" style="background-color: white;">
            <div class="toc-title"><i class="far fa-list-alt"></i>&nbsp;&nbsp;目录</div>
            <div id="toc-content"></div>
        </div>
    </div>
</div>

<!-- TOC 悬浮按钮. -->

<div id="floating-toc-btn" class="hide-on-med-and-down">
    <a class="btn-floating btn-large bg-color">
        <i class="fas fa-list-ul"></i>
    </a>
</div>


<script src="/jiodg45/libs/tocbot/tocbot.min.js"></script>
<script>
    $(function () {
        tocbot.init({
            tocSelector: '#toc-content',
            contentSelector: '#articleContent',
            headingsOffset: -($(window).height() * 0.4 - 45),
            collapseDepth: Number('0'),
            headingSelector: 'h2, h3, h4'
        });

        // modify the toc link href to support Chinese.
        let i = 0;
        let tocHeading = 'toc-heading-';
        $('#toc-content a').each(function () {
            $(this).attr('href', '#' + tocHeading + (++i));
        });

        // modify the heading title id to support Chinese.
        i = 0;
        $('#articleContent').children('h2, h3, h4').each(function () {
            $(this).attr('id', tocHeading + (++i));
        });

        // Set scroll toc fixed.
        let tocHeight = parseInt($(window).height() * 0.4 - 64);
        let $tocWidget = $('.toc-widget');
        $(window).scroll(function () {
            let scroll = $(window).scrollTop();
            /* add post toc fixed. */
            if (scroll > tocHeight) {
                $tocWidget.addClass('toc-fixed');
            } else {
                $tocWidget.removeClass('toc-fixed');
            }
        });

        
        /* 修复文章卡片 div 的宽度. */
        let fixPostCardWidth = function (srcId, targetId) {
            let srcDiv = $('#' + srcId);
            if (srcDiv.length === 0) {
                return;
            }

            let w = srcDiv.width();
            if (w >= 450) {
                w = w + 21;
            } else if (w >= 350 && w < 450) {
                w = w + 18;
            } else if (w >= 300 && w < 350) {
                w = w + 16;
            } else {
                w = w + 14;
            }
            $('#' + targetId).width(w);
        };

        // 切换TOC目录展开收缩的相关操作.
        const expandedClass = 'expanded';
        let $tocAside = $('#toc-aside');
        let $mainContent = $('#main-content');
        $('#floating-toc-btn .btn-floating').click(function () {
            if ($tocAside.hasClass(expandedClass)) {
                $tocAside.removeClass(expandedClass).hide();
                $mainContent.removeClass('l9');
            } else {
                $tocAside.addClass(expandedClass).show();
                $mainContent.addClass('l9');
            }
            fixPostCardWidth('artDetail', 'prenext-posts');
        });
        
    });
</script>

    

</main>




    <footer class="page-footer bg-color">
    
        <link rel="stylesheet" href="/jiodg45/libs/aplayer/APlayer.min.css">
<style>
    .aplayer .aplayer-lrc p {
        
        display: none;
        
        font-size: 12px;
        font-weight: 700;
        line-height: 16px !important;
    }

    .aplayer .aplayer-lrc p.aplayer-lrc-current {
        
        display: none;
        
        font-size: 15px;
        color: #42b983;
    }

    
    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body {
        left: -66px !important;
    }

    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body:hover {
        left: 0px !important;
    }

    
</style>
<div class="">
    
    <div class="row">
        <meting-js class="col l8 offset-l2 m10 offset-m1 s12"
                   server="netease"
                   type="playlist"
                   id="503838841"
                   fixed='true'
                   autoplay='false'
                   theme='#42b983'
                   loop='all'
                   order='random'
                   preload='auto'
                   volume='0.7'
                   list-folded='true'
        >
        </meting-js>
    </div>
</div>

<script src="/jiodg45/libs/aplayer/APlayer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script>

    
    <div class="container row center-align" style="margin-bottom: 0px !important;">
        <div class="col s12 m8 l8 copy-right">
            Copyright&nbsp;&copy;
            
                <span id="year">2019-2021</span>
            
            <span id="year">2019</span>
            <a href="/jiodg45/about" target="_blank">Longxiang.Guo</a>
            |&nbsp;Powered by&nbsp;<a href="https://hexo.io/" target="_blank">Hexo</a>
            |&nbsp;Theme&nbsp;<a href="https://github.com/blinkfox/hexo-theme-matery" target="_blank">Matery</a>
            <br>
            
            
            
            
            
            
            <span id="busuanzi_container_site_pv">
                |&nbsp;<i class="far fa-eye"></i>&nbsp;总访问量:&nbsp;<span id="busuanzi_value_site_pv"
                    class="white-color"></span>&nbsp;次
            </span>
            
            
            <span id="busuanzi_container_site_uv">
                |&nbsp;<i class="fas fa-users"></i>&nbsp;总访问人数:&nbsp;<span id="busuanzi_value_site_uv"
                    class="white-color"></span>&nbsp;人
            </span>
            
            <br>
            
            <br>
            
        </div>
        <div class="col s12 m4 l4 social-link social-statis">
    <a href="https://github.com/LongXiangGuo" class="tooltipped" target="_blank" data-tooltip="访问我的GitHub" data-position="top" data-delay="50">
        <i class="fab fa-github"></i>
    </a>



    <a href="mailto:290657563@qq.com" class="tooltipped" target="_blank" data-tooltip="邮件联系我" data-position="top" data-delay="50">
        <i class="fas fa-envelope-open"></i>
    </a>







    <a href="tencent://AddContact/?fromId=50&fromSubId=1&subcmd=all&uin=290657563" class="tooltipped" target="_blank" data-tooltip="QQ联系我: 290657563" data-position="top" data-delay="50">
        <i class="fab fa-qq"></i>
    </a>







</div>
    </div>
</footer>

<div class="progress-bar"></div>


    <!-- 搜索遮罩框 -->
<div id="searchModal" class="modal">
    <div class="modal-content">
        <div class="search-header">
            <span class="title"><i class="fas fa-search"></i>&nbsp;&nbsp;搜索</span>
            <input type="search" id="searchInput" name="s" placeholder="请输入搜索的关键字"
                   class="search-input">
        </div>
        <div id="searchResult"></div>
    </div>
</div>

<script type="text/javascript">
$(function () {
    var searchFunc = function (path, search_id, content_id) {
        'use strict';
        $.ajax({
            url: path,
            dataType: "xml",
            success: function (xmlResponse) {
                // get the contents from search data
                var datas = $("entry", xmlResponse).map(function () {
                    return {
                        title: $("title", this).text(),
                        content: $("content", this).text(),
                        url: $("url", this).text()
                    };
                }).get();
                var $input = document.getElementById(search_id);
                var $resultContent = document.getElementById(content_id);
                $input.addEventListener('input', function () {
                    var str = '<ul class=\"search-result-list\">';
                    var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
                    $resultContent.innerHTML = "";
                    if (this.value.trim().length <= 0) {
                        return;
                    }
                    // perform local searching
                    datas.forEach(function (data) {
                        var isMatch = true;
                        var data_title = data.title.trim().toLowerCase();
                        var data_content = data.content.trim().replace(/<[^>]+>/g, "").toLowerCase();
                        var data_url = data.url;
                        data_url = data_url.indexOf('/') === 0 ? data.url : '/' + data_url;
                        var index_title = -1;
                        var index_content = -1;
                        var first_occur = -1;
                        // only match artiles with not empty titles and contents
                        if (data_title !== '' && data_content !== '') {
                            keywords.forEach(function (keyword, i) {
                                index_title = data_title.indexOf(keyword);
                                index_content = data_content.indexOf(keyword);
                                if (index_title < 0 && index_content < 0) {
                                    isMatch = false;
                                } else {
                                    if (index_content < 0) {
                                        index_content = 0;
                                    }
                                    if (i === 0) {
                                        first_occur = index_content;
                                    }
                                }
                            });
                        }
                        // show search results
                        if (isMatch) {
                            str += "<li><a href='" + data_url + "' class='search-result-title'>" + data_title + "</a>";
                            var content = data.content.trim().replace(/<[^>]+>/g, "");
                            if (first_occur >= 0) {
                                // cut out 100 characters
                                var start = first_occur - 20;
                                var end = first_occur + 80;
                                if (start < 0) {
                                    start = 0;
                                }
                                if (start === 0) {
                                    end = 100;
                                }
                                if (end > content.length) {
                                    end = content.length;
                                }
                                var match_content = content.substr(start, end);
                                // highlight all keywords
                                keywords.forEach(function (keyword) {
                                    var regS = new RegExp(keyword, "gi");
                                    match_content = match_content.replace(regS, "<em class=\"search-keyword\">" + keyword + "</em>");
                                });

                                str += "<p class=\"search-result\">" + match_content + "...</p>"
                            }
                            str += "</li>";
                        }
                    });
                    str += "</ul>";
                    $resultContent.innerHTML = str;
                });
            }
        });
    };

    searchFunc('/jiodg45/search.xml', 'searchInput', 'searchResult');
});
</script>

    <!-- 回到顶部按钮 -->
<div id="backTop" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fas fa-arrow-up"></i>
    </a>
</div>


    <script src="/jiodg45/libs/materialize/materialize.min.js"></script>
    <script src="/jiodg45/libs/masonry/masonry.pkgd.min.js"></script>
    <script src="/jiodg45/libs/aos/aos.js"></script>
    <script src="/jiodg45/libs/scrollprogress/scrollProgress.min.js"></script>
    <script src="/jiodg45/libs/lightGallery/js/lightgallery-all.min.js"></script>
    <script src="/jiodg45/js/matery.js"></script>

    <!-- Baidu Analytics -->

    <!-- Baidu Push -->

<script>
    (function () {
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https') {
            bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
        } else {
            bp.src = 'http://push.zhanzhang.baidu.com/push.js';
        }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
</script>

    
    <script src="/jiodg45/libs/others/clicklove.js" async="async"></script>
    
    
    <script async src="/jiodg45/libs/others/busuanzi.pure.mini.js"></script>
    

    

    

    <!--腾讯兔小巢-->
    
    

    

    

    
    <script src="/jiodg45/libs/instantpage/instantpage.js" type="module"></script>
    

</body>

</html>
